package com.woniuxy.lab.woniu_lab.service.impl;

import cn.hutool.core.lang.Snowflake;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.request.AlipayTradePagePayRequest;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.woniuxy.lab.woniu_lab.config.AlipayConfig;
import com.woniuxy.lab.woniu_lab.exception.WebException;
import com.woniuxy.lab.woniu_lab.model.Charge;
import com.woniuxy.lab.woniu_lab.dao.ChargeDao;
import com.woniuxy.lab.woniu_lab.model.User;
import com.woniuxy.lab.woniu_lab.service.ChargeService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.woniuxy.lab.woniu_lab.service.UserService;
import com.woniuxy.lab.woniu_lab.service.dto.ChargeDto;
import lombok.extern.slf4j.Slf4j;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.messaging.Message;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.Objects;

/**
 * <p>
 * 充值记录表 服务实现类
 * </p>
 *
 * @author Silas
 * @since 2023-03-15
 */
@Service
@Slf4j
@Transactional
public class ChargeServiceImpl extends ServiceImpl<ChargeDao, Charge> implements ChargeService {
    @Resource
    private ChargeDao chargeDao;

    @Resource
    private UserService userService;

    @Resource
    private RocketMQTemplate rocketMQTemplate;

    @Value("${aliPay.notifyUrl}")
    private String notifyUrl;

    @Value("${aliPay.returnUrl}")
    private String returnUrl;

    @Override
    public IPage<ChargeDto> findMy(Integer userId,Integer page,Integer size) {

        IPage<Charge> iPage = new Page<>(page == null ? 1 : page, size == null ? 4 : size);
        IPage<Charge> page1 = chargeDao.selectPage(iPage, new QueryWrapper<Charge>()
                .eq("user_id", userId).orderByDesc("create_time")
        );
        IPage<ChargeDto> chargeDtoIPage = iPage.convert(u -> {
            ChargeDto chargeDto = new ChargeDto();
            BeanUtils.copyProperties(u, chargeDto);
            return chargeDto;
        });
        return chargeDtoIPage;
    }

    @Override
    public String createOrder(BigDecimal money){
        User user = userService.assertUser();
        //判断该用户是否还存在未支付的订单,如果存在提示用户先完成或取消该订单后在充值
        Charge charge = getOne(new QueryWrapper<Charge>().eq("user_id", user.getId()).eq("status", "PAYING"));
        if (charge!=null) throw new WebException(400,"您有订单号("+charge.getNo()+")处于充值中,请充值完成或取消该订单后再进行充值");
        //订单名称，必填(传给支付宝)
        String subject = "充值蜗牛币"+ money.toString() +"个";
        //商户订单号，商户网站订单系统中唯一订单号，必填
        Snowflake snowflake = new Snowflake(1, 1);
        String no = "WNB"+snowflake.nextIdStr();

        String result = aliPay(no, money,subject);
        //判断支付宝返回的内容是否存在
        if (result==null || result.equals("")){
            log.warn("支付宝返回异常,赶紧检查问题");
            throw new WebException(500,"非常抱歉,支付出现异常,请联系管理员");
        }
        //保存充值记录
        Charge addCharge = new Charge();
        addCharge.setNo(no);
        addCharge.setInfo(subject);
        addCharge.setUserId(user.getId());
        addCharge.setCreateTime(LocalDateTime.now());
        addCharge.setMoney(money);
        addCharge.setStatus("PAYING");
        save(addCharge);
        //定时1小时,查询订单状态,如果未支付则关闭订单(使用消息队列)
        Message<String> message = MessageBuilder.withPayload(no).build();
        rocketMQTemplate.syncSend("cancel_charge_topic",message,3000,17);
        return result;
    }


    //支付宝回调成功,成功记录消息
    @Override
    public void paySuccess(String outTradeNo) {
        Charge charge = getOne(new QueryWrapper<Charge>().eq("no", outTradeNo));
        if (charge==null){
            log.warn("数据异常{}",outTradeNo);
            throw new WebException(2001,"订单数据异常数据异常");
        }
        charge.setStatus("SUCCESS");
        //给用户加钱
        User user = userService.getById(charge.getUserId());
        user.setBalance(user.getBalance().add(charge.getMoney()));
        updateById(charge);
        userService.updateById(user);
    }


    //重新支付
    @Override
    public String continuePay(String no)  {
        User user = userService.assertUser();
//        Charge charge = getOne(new QueryWrapper<Charge>().eq("no", no).eq("user_id", user.getId()));
        Charge charge = getOne(new QueryWrapper<Charge>().eq("no", no));
        //如果查询不到订单
        if (charge==null) throw new WebException(1001,"订单数据异常,请联系管理员");
        //如果该订单不属于当前用户
        if (!Objects.equals(charge.getUserId(), user.getId())) throw new WebException(1001,"无法支付,该订单不属于您");
        //如果订单已经支付
        if (charge.getStatus().equals("SUCCESS")) throw new WebException(1001,"该订单已经支付,无法再次支付!");
        //该订单已经取消
        if (charge.getStatus().equals("FAIL")) throw new WebException(1001,"该订单已经取消,无法继续支付!");
        return aliPay(no, charge.getMoney(), "订单" + no + "重新支付");
    }

    @Override
    public void cancelPay(String no) {
        User user = userService.assertUser();
        Charge charge = getOne(new QueryWrapper<Charge>().eq("no", no));
        if (charge==null) throw new WebException(1001,"该订单不存在");
        if (!Objects.equals(charge.getUserId(), user.getId())) throw new WebException(1001,"该订单不属于您,无法取消!!");
        if (charge.getStatus().equals("SUCCESS")) throw new WebException(1001,"该订单已经支付,无法取消!");
        if (charge.getStatus().equals("FAIL")) throw new WebException(1001,"该订单已经取消,无需再次取消!");
        charge.setStatus("FAIL");
        charge.setExpireTime(LocalDateTime.now());
        updateById(charge);
    }

    /**
     *
     * @param orderNo 订单编号
     * @param money 价格
     * @return 支付宝支付html
     */
    private String aliPay(String orderNo,BigDecimal money,String subject){
        AlipayClient alipayClient = new DefaultAlipayClient(
                AlipayConfig.gatewayUrl,
                AlipayConfig.appId,
                AlipayConfig.merchantPrivateKey,
                "json",
                AlipayConfig.charset,
                AlipayConfig.alipayPublicKey,
                AlipayConfig.signType);


        AlipayTradePagePayRequest alipayRequest = new AlipayTradePagePayRequest();
//        alipayRequest.setReturnUrl(AlipayConfig.returnUrl);
//        alipayRequest.setNotifyUrl(AlipayConfig.notifyUrl);
        alipayRequest.setReturnUrl(returnUrl);
        alipayRequest.setNotifyUrl(notifyUrl);

        String total_amount = "";
        String out_trade_no = "";
        try {
            out_trade_no = new String(orderNo.getBytes("ISO-8859-1"),"UTF-8");
            total_amount = new String(money.toString().getBytes("ISO-8859-1"),"UTF-8");
        } catch (UnsupportedEncodingException e) {
            throw new WebException(5000,"数据解析异常,请联系管理员");
        }
        //付款金额，必填

        //商品描述，可空
        String body = "蜗牛币用户购买本网站上的靶场服务,用于安全实验";

        alipayRequest.setBizContent("{\"out_trade_no\":\""+ out_trade_no +"\","
                + "\"total_amount\":\""+ total_amount +"\","
                + "\"subject\":\""+ subject +"\","
                + "\"body\":\""+ body +"\","
                + "\"product_code\":\"FAST_INSTANT_TRADE_PAY\"}");

        try {
            return alipayClient.pageExecute(alipayRequest).getBody();
        } catch (AlipayApiException e) {
            throw new WebException(5001,"支付宝支付异常,请联系管理员");

        }
    }
}
